home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1999
/
MacHack 1999.toast
/
The Hacks
/
DesktopDoubler
/
Nub
/
Nub.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-06-25
|
6KB
|
306 lines
#define DISABLE_LOCAL_CALLTRACE 1 // Set to 1 to disable Call Traces for this file.
#define DISABLE_LOCAL_DEBUG 0 // Set to 1 to disable all debugging for this file.
#include "DebugUtils.h"
#include <Errors.h>
#include <Gestalt.h>
#include "ContextUtils.h"
#include "DesktopDoubler.h"
#include "Nub.h"
#include "PatchHarness.h"
#include "ProcInfo.h"
#include "Version.h"
#ifdef __cplusplus
extern "C" {
#endif
extern void __InitCode__(void);
extern void __destroy_global_chain(void);
#if APPBUILD
OSStatus NubMain(Handle code);
#else
pascal OSStatus main(Handle code);
#endif
static OSStatus LoadNub(Handle code);
static pascal OSStatus UnloadNub(Handle *code);
static Boolean isPressed(UInt8 keyCode);
#if GENERATING68K && !GENERATINGCFM && __A5__
void RememberA5(void);
#endif
#ifdef __cplusplus
}
#endif
#if GENERATINGPOWERPC
ProcInfoType __procinfo = uppNubLoadProcInfo;
static RoutineDescriptor gUnloadNubRD = BUILD_ROUTINE_DESCRIPTOR(uppNubUnloadProcInfo,UnloadNub);
static RoutineDescriptor *gUnloadNubUPP = (RoutineDescriptor*)&gUnloadNubRD;
#else
static NubUnloadUPP gUnloadNubUPP = UnloadNub;
#endif
NubInfo *gInfo = NULL;
static Handle gCode = NULL;
static UInt32 gAbortLoad = 0;
static Boolean gBootInstall = false;
static Boolean gDestructOnUnload = false;
#if APPBUILD
OSStatus NubMain(Handle code)
#pragma mark NubMain
#else
pascal OSStatus main(Handle code)
#endif
{
#if !APPBUILD
GlobalContext globals;
#endif
OSStatus err;
#if DEBUG
// Check for CapsLock.
if (isPressed(0x39))
{
DebugStr("\pNub abort checkpoint");
if (gAbortLoad)
{
dprintf(kDConPrefix "LoadNub aborted\n");
return -1;
}
}
#endif
// Save application global A5 world.
#if GENERATING68K && !GENERATINGCFM && __A5__
RememberA5();
#endif
// 68K code resources need to construct their own static C++ data objects (A4 must be
// setup). We only need to do this for 68K because it'll be automagically constructed
// by the CFM init routine for a PowerPC code resource.
#if !GENERATINGPOWERPC && !APPBUILD
__InitCode__();
#endif
// Install the Nub, if this fails we just forward the error.
// Our caller has already detached us and if we return an error it
// is responsible for unloading us, otherwise we will stick around.
err = LoadNub(code);
if (err != noErr)
{
dprintf(kDConPrefix "LoadNub failed: %ld\n",err);
// Code resources need to destruct their own static C++ data objects (A4 must be
// setup for 68K). We must do this PowerPC code resources too, as CFM termination
// routines won't be invoked when a code resource is unloaded.
#if !APPBUILD
__destroy_global_chain();
#endif
}
else
gDestructOnUnload = true;
return err;
}
OSStatus LoadNub(Handle code)
{
THzContext zone(SystemZone());
NubInfo *info;
SInt32 result;
OSStatus err;
// Check Gestalt to determine install/reinstall.
err = Gestalt(kNubSelector,(SInt32*)&info);
if (err != noErr)
info = NULL;
// The INIT must be loaded first to bootstrap the debugging application version,
// otherwise we won't be able to install any patches.
#if APPBUILD
if ((err != noErr) || (info == NULL))
return notOpenErr;
#endif
// Check for Nub already being present and loaded.
if ((err == noErr) && info && (info->signature == kNubSignature))
return opWrErr;
// If the Gestalt selector didn't exist, or the permanent data structures haven't
// been setup (which means we haven't patched anything yet), this is an install.
if ((err != noErr) || (info == NULL))
{
if (info == NULL)
{
// Allocate system exposed permanent data structures.
info = (NubInfo*)NewPtrSysClear(sizeof(NubInfo));
if (info == NULL)
{
err = MemError();
dprintf(kDConPrefix "Couldn't allocate NubInfo: %ld\n",err);
return err;
}
}
if (err != noErr)
{
// Install system wide patch harness.
err = InstallPatchHarness(&info->patchList);
if (err != noErr)
{
dprintf(kDConPrefix "InstallPatchHarness failed: %ld\n",err);
DisposePtr((Ptr)info);
return err;
}
}
// Setup pointer to NubInfo as Gestalt selector result.
err = InstallPatch(info->patchList,'GSEL',(UniversalProcPtr)info);
if (err != noErr)
{
dprintf(kDConPrefix "Couldn't install '.4%s' Gestalt selector: %ld\n",err);
DisposePtr((Ptr)info);
return err;
}
// Set boot time flag.
gBootInstall = true;
}
// Setup globals.
gCode = code;
gInfo = info;
// Setup NubInfo record.
gInfo->signature = kNubSignature;
*(UInt32*)&gInfo->version = kNubVersion;
*(UInt32*)&gInfo->compatible = kNubCompatible;
gInfo->unloadProc = gUnloadNubUPP;
// Make it go....
err = InitDesktopDoubler();
if (err != noErr)
{
dprintf(kDConPrefix,"InitDesktopDoubler failed: %ld\n",err);
UnloadNub(&gCode);
return err;
}
#if DEBUG
{
UInt32 vers = kNubVersion;
char text[32];
dprintf(kDConPrefix "DesktopDoubler %s installed\n",NumVersionToCString(text,(NumVersion*)&vers));
}
#endif
return noErr;
}
pascal OSStatus UnloadNub(Handle *code)
{
GlobalContext globals;
THzContext zone(SystemZone());
PatchDesc *patch;
// Make it stop...
TermDesktopDoubler();
// Remove all patches.
patch = gInfo->patchList;
while(patch != NULL)
{
// Don't remove our special GestaltSelector patch.
if ((patch->type != 'GSEL') && patch->remove)
CallPatchRemoveProc(patch->remove,patch);
patch = patch->next;
}
// Clear NubInfo record.
gInfo->signature = 0;
gInfo->unloadProc = NULL;
// Caller must dispose.
#if APPBUILD
*code = NULL;
#else
*code = gCode;
#endif
if (gDestructOnUnload)
{
// Code resources need to destruct their own static C++ data objects (A4 must be
// setup for 68K). We must do this PowerPC code resources too, as CFM termination
// routines won't be invoked when a code resource is unloaded.
#if !APPBUILD
__destroy_global_chain();
#endif
gDestructOnUnload = false;
}
return noErr;
}
Boolean isPressed(UInt8 keyCode)
{
UInt8 km[16];
GetKeys((SInt32*)&km[0]);
return ((km[keyCode >> 3] >> (keyCode & 7)) & 1);
}
#if GENERATING68K && !GENERATINGCFM && __A5__
asm void RememberA5(void)
{
LEA @A5Storage,A0
MOVE.L A5,(A0)
RTS
entry GetCurrentA5
MOVE.L @A5Storage,D0
RTS
@A5Storage:
DC.L 0x00000000
}
#endif